#!/usr/bin/env python
# -*- coding: utf-8 -*-
#本代码来自所出售产品的淘宝店店主编写
#未经受权不得复制转发
#淘宝店：https://fengmm521.taobao.com/
#再次感谢你购买本店产品
import os,sys
import cv2
import numpy as np
import time
import httpUtil
import serialUtil
import cmdUtil
import fandCom
import cam

from queue import Queue

CMDQUEUE = Queue()  #多线程发送鼠标动作数据的队列

cobj = None

def startSerial():
    dev = fandCom.getComPort()                              #获取ch340芯片的串口端口号
    net_thread = serialUtil.serialThread(CMDQUEUE,dev)
    net_thread.setDaemon(True)
    net_thread.start()                                      #启动蓝牙串口线程
    cmdUtil.initCmdUtil(CMDQUEUE)                           #设置串口发送线程数据接收队列


#摄像头图像旋转处理函数
def imgRotate(img):
    # img_rot = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE) #图片逆时针旋转90度
    img_rot = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)          #图片顺时针旋转90度
    return img_rot

#鼠标操作事件处理
def on_Event_mouse(camobj,event, x, y,flags, param):
        #左键按下
        if event == cv2.EVENT_LBUTTONDOWN:
            # self.mPressFunc(x,y,flags)
            print('lbtn down')
            camobj.spt = (int(x*camobj.scalImg/camobj.showScal),int(y*camobj.scalImg/camobj.showScal))
            if camobj.p4s:
                print('mouse_down',camobj.spt[0],camobj.spt[1],flags,param)
                cmdUtil.press(camobj.spt[0],camobj.spt[1])
            else:
                camobj.isDrawBox = True
        #左键抬起
        elif event == cv2.EVENT_LBUTTONUP:
            # self.mReleaseFunc(x,y,flags)
            print('lbtn up')
            camobj.ept = (int(x*camobj.scalImg/camobj.showScal),int(y*camobj.scalImg/camobj.showScal))
            if camobj.p4s:
                cmdUtil.release(camobj.ept[0],camobj.ept[1])
                print('mouse_up',camobj.ept[0],camobj.ept[1],flags,param)
            else:
                res,tmpls = camobj.testLinesInBox()
                print(tmpls,len(camobj.savelines))
                if res:
                    camobj.savelines.append(tmpls)
                if len(camobj.savelines) >= 4:
                    camobj.lines = []
                    camobj.p4s = camobj.getImg4P(camobj.savelines)
                    print(camobj.savelines,camobj.p4s)
                    if camobj.p4s[0] and camobj.p4s[1] and camobj.p4s[2] and camobj.p4s[3]:
                        camobj.setCamState(3)
                    else:
                        camobj.p4s = []
                camobj.isDrawBox = False
        #鼠标移动
        elif event == cv2.EVENT_MOUSEMOVE:
            camobj.mpt = (int(x*camobj.scalImg/camobj.showScal),int(y*camobj.scalImg/camobj.showScal))
            if camobj.p4s:
                if flags & 1:
                    cmdUtil.press(camobj.mpt[0],camobj.mpt[1])
                else:
                    cmdUtil.release(camobj.mpt[0],camobj.mpt[1])
                print('mouse_move',camobj.mpt[0],camobj.mpt[1],flags,param)

def listCamDevices(cname = None):
    from PyCameraList.camera_device import list_video_devices
    cameras = list_video_devices()
    camdict = dict(cameras)
    print(camdict)
    if cname:
        finds = []
        for k,v in camdict.items():
            if v.find(cname) != -1:
                finds.append(k)
                # print('used device:%d,%s'%(k,v))
        if finds:
            return finds

#初始化摄像头对象
def initCam(camobj):
    camobj.deivceID = 1                 #设置摄像头编号
    # camobj.iW = 3840                    #摄像头宽度像素
    # camobj.iH = 2160                    #摄像头高度像素
    camobj.scalImg = 5.0                #因为摄像头画面太大,电脑显示器没有办法显示完整,在显示时对图片的缩小比例值

    camobj.setWH(3840,2160)
    #打开摄像头
    camobj.cap = cv2.VideoCapture(camobj.deivceID,cv2.CAP_MSMF)
    # camobj.cap = cv2.VideoCapture(self.deivceID,cv2.CAP_OPENCV_MJPEG)
    # cv2.CAP_MSMF:windows的MSMF捕获，效果最好，但摄像头打开速度非常慢
    # cv::CAP_ANY: 尝试使用任何可用的后端进行捕获。
    # cv::CAP_VFW: Video for Windows（VFW）捕获API。
    # cv::CAP_DSHOW: DirectShow捕获API。摄像头打开速度很快，但画面帧率很低很低
    # cv::CAP_FFMPEG: 使用FFmpeg库进行视频捕获。代码不支持图片格式
    # cv::CAP_GIGANETIX: Giganetix GigEVision SDK捕获API。
    # cv::CAP_OPENCV_MJPEG: OpenCV内置的MJPEG捕获器。代码不支持图片格式
    time.sleep(1)
    # camobj.cap.set(cv2.CAP_PROP_FOURCC,cv2.VideoWriter.fourcc('M','J','P','G'))#'Y','U','Y','2'
    camobj.cap.set(cv2.CAP_PROP_FRAME_WIDTH, camobj.iW)  # 设置摄像头宽度
    camobj.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, camobj.iH)  # 设置摄像头高度
    # camobj.cap.set(cv2.CAP_PROP_FPS,15)
    time.sleep(1)
    # camobj.cap.set(cv2.CAP_PROP_EXPOSURE,0)  #曝光度
    # camobj.cap.set(cv2.CAP_PROP_CONTRAST,1)   #对比度
    # camobj.cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)
    print('宽:', camobj.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    print('高:', camobj.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    print('帧率:', camobj.cap.get(cv2.CAP_PROP_FPS))
    print('亮度:', camobj.cap.get(cv2.CAP_PROP_BRIGHTNESS))
    print('对比度:', camobj.cap.get(cv2.CAP_PROP_CONTRAST))
    print('饱和度:', camobj.cap.get(cv2.CAP_PROP_SATURATION))
    print('色调:', camobj.cap.get(cv2.CAP_PROP_HUE))
    print('曝光度:', camobj.cap.get(cv2.CAP_PROP_EXPOSURE))
    
    camobj.loadP4s()                                        #如果之前有设置画面裁切坐标和摄像头焦距,则使用裁切画面和焦距
    cmdUtil.set_screenWH(camobj.catW,camobj.catH)           #初始化设置蓝牙点击器对应的屏幕宽高,这个值和显示画面有关,和是否裁切也有关

def main():
    global cobj
    cobj = None
    listCamDevices()
    startSerial()
    lvalues = []
    lcount = 50
    isGetLp = False
    isCAT = False
    focus = 0
    cobj = cam.camObj(initFunc = initCam,mouseEventFunc = on_Event_mouse)                                    #初始化摄像头对象
    cv2WinName = 'caminit'
    cv2.namedWindow(cv2WinName)
    cv2.setMouseCallback(cv2WinName, cobj.onMouseEvent)    #设置鼠标回调函数
    if cobj.p4s:                                        #检测是否已经保存摄像头画面裁切数据
        isCAT = True
    while True:
        #获取基础图片或者裁切后的图片
        img = cobj.getRotateImg()
        if isCAT:
            cobj.setCamState(4)
        #缩放图片,以方便显示
        rimg = cobj.resizeImg(img)
        cv2.imshow(cv2WinName, rimg)
        if isGetLp:
            l = cobj.Laplacian(img)
            print(len(lvalues),l)
            lvalues.append(l)
            if len(lvalues) >= lcount:
                mean1 = np.mean(lvalues)        #平均值
                lvalues = []
                print('mean lap:',mean1)        #精细设置焦距时自动计算当前焦距下的图片清晰度的平平均值.可以与其他焦距的植进行对比,当这个值达到最大时,就是最清晰的焦距
                isGetLp = False
        key = cv2.waitKey(1)
        if key > 0:
            if key & 0xFF == 0x1B:
                exit(0)
            elif key & 0xFF == ord('-'):       
                if not isCAT:
                    cobj.setCamState(2)         #设置摄像头裁切时,停止使用新图像,锁定灰度直线图片
            elif key & 0xFF == ord('='):        #设置摄像头裁切时,开始使用新图像,停止屏幕灰度图片直线检测,并清除保存的屏幕裁切数据
                cobj.setCamState(0)
                cobj.cleanP4s()                 #清除保存的画面裁切坐标
                isCAT = False
            elif key & 0xFF == 0x20: #空格 
                if not isCAT:
                    cobj.setCamState(1)         #使用灰度图像,并检测图片中直线线条用绿色显示,以方便屏幕尺寸图像裁切
                else:
                    cobj.saveFocus()            #保存摄像头手动设置的当前焦距到p4s.txt文件
            elif key & 0xFF == ord('l'):        #精细设置焦距时自动计算当前焦距下的图片清晰度的平平均值.可以与其他焦距的植进行对比,当这个值达到最大时,就是最清晰的焦距
                print('l')
                isGetLp = True
            elif key == ord('o'):                       #对摄像头图像进行文字识别
                try:
                    ocrdata = httpUtil.httpPostImg(img,ip='192.168.88.253',port = 8889)
                    for i,v in enumerate(ocrdata[0]):
                        print(v)
                        if v[1][0].find('声音和振动') != -1:    #查找文字框中是否包含'声音和振动'
                           pt = cobj.findCenterPoint(v[0])     #查找文字框的中心点
                           print(v,pt)
                           cmdUtil.click(pt[0],pt[1])          #点击文字框的中心点
                except:
                    print('ocr error')
            elif key == ord("q"):                       #摄置摄像头焦距+100
            # 通过s键保存图片，并退出。
                focus += 100   
                if focus >= 1023:
                    focus = 1023
                cobj.setFocus(focus)
                time.sleep(0.1)
            elif key == ord("a"):                       #摄置摄像头焦距-100 
                focus -= 100   
                if focus <= 0:
                    focus = 0
                cobj.setFocus(focus)
                time.sleep(0.1)
            elif key == ord("w"):                       #摄置摄像头焦距+10
            # 通过s键保存图片，并退出。
                focus += 10   
                if focus >= 1023:
                    focus = 1023
                cobj.setFocus(focus)
                time.sleep(0.1)
            elif key == ord("s"):                       #摄置摄像头焦距-10
                focus -= 10   
                if focus <= 0:
                    focus = 0
                cobj.setFocus(focus)
                time.sleep(0.1)
            elif key == ord("e"):                      #摄置摄像头焦距+1
            # 通过s键保存图片，并退出。
                focus += 1   
                if focus >= 1023:
                    focus = 1023
                cobj.setFocus(focus)
                time.sleep(0.1)
            elif key == ord("d"):                     #摄置摄像头焦距-1
                focus -= 1   
                if focus <= 0:
                    focus = 0
                cobj.setFocus(focus)
                time.sleep(0.1)
            elif key == ord('c'):                     #完成摄像头画图裁切或关闭摄像头画面裁切\
                if cobj.loadP4s():
                    isCAT = True
                    cobj.setCamState(4)
                    cmdUtil.set_screenWH(cobj.catW,cobj.catH)           #初始化设置蓝牙点击器对应的屏幕宽高
                time.sleep(0.1)
            elif key == ord('p'):                     #保存当前显示的图片
                savepth = 'imgout'
                if not os.path.exists(savepth):
                    os.makedirs(savepth)
                spth = savepth + os.sep + str(int(time.time())) + '.jpg'
                print(spth)
                cv2.imwrite(spth, img)              #保存旋转裁切后的图片
                # cv2.imwrite(spth, cobj.baseImg)   #保存摄像头获取到的原始图片


if __name__ == '__main__':  
    args = sys.argv
    if len(args) > 1:
        listCamDevices()
    else:
        main()
